
package 网络编程;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.net.ServerSocket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
//import java.util.Scanner;
import java.io.DataInputStream;
import java.io.DataOutputStream;
/*
public class 模拟ServiceTcp {
    public static void main(String[] args) {
        
        System.out.println("service......");
        try( //ss = null;
      		ServerSocket ss = new ServerSocket(6666);
            Socket socket = ss.accept();
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
      	  System.out.println("打印当前连接的客户端对象: " + socket.getInetAddress());
            
            while (true) {
                String receive = dis.readUTF();
                System.out.println("来自客户端的数据：" + receive);
                dos.writeUTF("收到了是多少");
                dos.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
*/
public class 模拟ServiceTcp {
   public static void main(String[] args) throws IOException {
       ServerSocket ss = new ServerSocket(6663); // 监听指定端口
       System.out.println("server is running...");
       for (;;) {//如果ServerSocket监听成功，我们就使用一个无限循环来处理客户端的连接：
           Socket sock = ss.accept();//监测客户连接，如果没有客户连接进来，一直等待
           System.out.println("connected from " + sock.getRemoteSocketAddress());
           Thread t = new Handler0(sock);
           t.start();//监测到客户连接，启动一个线程处理客户连接线程
       }
   }
}

class Handler0 extends Thread {
   Socket sock;

   public Handler0(Socket sock) {
       this.sock = sock;
   }

   @Override
   public void run() {
       try (InputStream input = this.sock.getInputStream()) {
           try (OutputStream output = this.sock.getOutputStream()) {
               handle0(input, output);
           }
       } catch (Exception e) {
           try {
               this.sock.close();
           } catch (IOException ioe) {
           }
           System.out.println("client disconnected.");
       }
   }

   private void handle0(InputStream input, OutputStream output) throws IOException {
       var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
       var reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
       writer.write("hello\n");//写入输出流，将被客户端接收
       writer.flush();
       for (;;) {
           String s = reader.readLine();
           if (s.equals("bye")) {
               writer.write("bye\n");
               writer.flush();
               break;
           }
           System.out.println("client input:"+s);
           writer.write("ok: " + s + "\n");//写入输出流，将被客户端接收
           writer.flush();
       }
   }
}
/*
注意到代码ss.accept()表示每当有新的客户端连接进来后，就返回一个Socket实例，这个Socket实例就是用来和刚连接的客户端进行通信
的。由于客户端很多，要实现并发处理，我们就必须为每个新的Socket创建一个新线程来处理，这样，主线程的作用就是接收新的连接，每当收到
新连接后，就创建一个新线程进行处理。

我们在多线程编程的章节中介绍过线程池，这里也完全可以利用线程池来处理客户端连接，能大大提高运行效率。

如果没有客户端连接进来，accept()方法会阻塞并一直等待。如果有多个客户端同时连接进来，ServerSocket会把连接扔到队列里，然后
一个一个处理。对于Java程序而言，只需要通过循环不断调用accept()就可以获取新的连接。
*/